<template>
  <div class="message-container">
    <!-- 顶部导航，保持与组织架构一致 -->
    <div class="header-wrapper">
      <div class="header">
        <div class="back-icon" @click="goBack">
          <van-icon name="arrow-left" />
        </div>
        <div class="header-title">
          {{ isNotificationMode ? "消息通知" : "公告管理" }}
        </div>
        <div
          class="add-btn"
          v-if="!isNotificationMode && isAdmin"
          @click="openAddDialog"
        >
          <!-- 使用实际存在的资源路径 -->
          <img src="@/assets/homeOther/plus_message.png" alt="新增" />
        </div>
      </div>

      <!-- 搜索框 -->
      <div class="search-container">
        <van-search
          v-model="keyword"
          :placeholder="isNotificationMode ? '搜索消息标题' : '搜索公告标题'"
          shape="round"
          @search="onSearch"
        />
      </div>
    </div>

    <!-- 筛选栏 -->
    <div class="filter-bar">
      <van-dropdown-menu class="dropdown_menu_style">
        <!-- 通知/公告模式均保留“类型”筛选 -->
        <van-dropdown-item v-model="type" :options="typeOptions" />
        <!-- “发布范围”筛选仅在公告模式显示 -->
        <van-dropdown-item
          v-if="!isNotificationMode"
          v-model="scope"
          :options="scopeOptions"
        />
      </van-dropdown-menu>
      <div class="count_length">
        共 <span style="color: #2764eb"> {{ total }}</span> 条
      </div>
    </div>

    <!-- 列表 -->
    <div class="list-container">
      <div
        v-for="item in list"
        :key="item.id"
        class="message-card"
        @click="openDetail(item)"
      >
        <div class="message-top">
          <div class="tags">
            <!-- 等级标签：通知/公告模式都显示 -->
            <span v-if="item.level === 'urgent'" class="tag tag-urgent"
              >紧急</span
            >
            <span
              v-else-if="item.level === 'important'"
              class="tag tag-important"
              >重要</span
            >
            <span v-else class="tag tag-normal">普通</span>
            <!-- 发布范围标签（仅公告模式，根据 allowType 映射显示） -->
            <template v-if="!isNotificationMode">
              <span v-if="item.scope === 'all'" class="tag tag-all">全体</span>
              <span v-else-if="item.scope === 'department'" class="tag tag-all"
                >部门</span
              >
              <span v-else class="tag tag-all">员工</span>
            </template>
          </div>
          <div
            v-if="!isNotificationMode"
            :class="['status', statusClass(item.status)]"
          >
            {{ statusText(item.status) }}
          </div>
          <div
            v-else
            :class="['status', item.isReadFlag ? 'status-read' : 'status-unread']"
          >
            {{ item.isReadFlag ? '已读' : '未读' }}
          </div>
        </div>
        <div class="title-row">{{ item.title }}</div>
        <div class="bottom-row">
          <div class="dept-date">{{ item.department }} · {{ item.date }}</div>
          <div class="actions" v-if="!isNotificationMode && isAdmin">
            <div
              class="circle-btn"
              :class="{ disabled: item.status !== 'published' }"
              @click.stop="onRevoke(item)"
            >
              <img src="@/assets/homeOther/oa_revoke_message.png" alt="撤回" />
            </div>
            <div
              class="circle-btn"
              :class="{ disabled: item.status === 'published' }"
              @click.stop="onPublish(item)"
            >
              <img src="@/assets/homeOther/oa_push_message.png" alt="发布" />
            </div>
          </div>
        </div>
      </div>

      <van-empty
        v-if="!list.length && !loading"
        :description="isNotificationMode ? '暂无消息' : '暂无公告'"
      />
      <div style="padding: 20px; text-align: center" v-if="loading">
        <van-loading size="24px" color="#1989fa">加载中...</van-loading>
      </div>
    </div>
  </div>

  <!-- 新增公告弹窗 -->
  <van-popup
    v-model:show="showAddDialog"
    round
    :closeable="true"
    position="center"
    :close-on-click-overlay="true"
    @closed="onAddDialogClosed"
    class="add-dialog"
  >
    <div class="add-dialog__header">
      <div class="title">{{ isEditMode ? "修改公告" : "新增公告" }}</div>
    </div>
    <div class="add-dialog__body">
      <!-- 公告标题 -->
      <div class="form-item">
        <div class="label">公告标题 <span class="required">*</span></div>
        <van-field v-model="addTitle" placeholder="请输入公告标题" />
      </div>

      <!-- 类型与范围 -->
      <div class="form-row">
        <div class="form-item half">
          <div class="label">公告类型</div>
          <van-field
            readonly
            is-link
            :model-value="typeLabelMap[addType]"
            placeholder="请选择公告类型"
            @click="showTypePicker = true"
          />
        </div>
        <div class="form-item half">
          <div class="label">发布范围 <span class="required">*</span></div>
          <van-field
            readonly
            is-link
            :model-value="scopeLabelMap[addScope]"
            placeholder="请选择发布范围"
            @click="showScopePicker = true"
          />
        </div>
      </div>

      <!-- 指定对象（根据范围动态加载） -->
      <div class="form-item" v-if="addScope !== 'all'">
        <div class="label">指定对象</div>
        <div class="chips">
          <span
            v-for="t in availableTargets"
            :key="t.id"
            class="chip"
            :class="{ active: selectedTargetIds.includes(Number(t.id)) }"
            @click="toggleTarget(Number(t.id))"
            >{{ t.name }}</span
          >
        </div>
      </div>

      <!-- 附件上传（放在指定对象下面） -->
      <div class="form-item uploader-field">
        <div class="uploader-head">
          <div class="label upload_label">附件上传</div>
          <button
            type="button"
            class="uploader-add-btn"
            aria-label="添加附件"
            @click="openMessageUploaderInput($event)"
          >
            <van-icon name="add-o" />
          </button>
        </div>
        <VantUploader
          ref="messageUploaderRef"
          v-model="messageFileList"
          :max-file-count="5"
          :max-file-size-m-b="10"
          :show-upload-button="false"
        />
      </div>

      <!-- 公告内容 -->
      <div class="form-item">
        <div class="label">公告内容 <span class="required">*</span></div>
        <van-field
          v-model="addContent"
          type="textarea"
          rows="3"
          placeholder="请输入公告内容..."
          :maxlength="500"
          show-word-limit
        />
      </div>
    </div>

    <div class="add-dialog__footer">
      <van-button round class="btn-cancel" @click="showAddDialog = false">
        取消
      </van-button>
      <van-button
        round
        type="primary"
        class="btn-submit"
        :loading="isSubmittingAdd"
        :disabled="isSubmittingAdd"
        @click="onSubmitAdd"
      >
        {{ isEditMode ? "修改" : "新增" }}
      </van-button>
    </div>
  </van-popup>

  <!-- 类型选择器 -->
  <van-popup v-model:show="showTypePicker" position="bottom" round>
    <van-picker
      :columns="addTypePickerColumns"
      @confirm="onTypeConfirm"
      @cancel="showTypePicker = false"
    />
  </van-popup>

  <!-- 范围选择器 -->
  <van-popup v-model:show="showScopePicker" position="bottom" round>
    <van-picker
      :columns="addScopePickerColumns"
      @confirm="onScopeConfirm"
      @cancel="showScopePicker = false"
    />
  </van-popup>

  <!-- 详情弹窗 -->
  <van-popup
    v-model:show="showDetailDialog"
    round
    closeable
    position="center"
    @closed="onDetailDialogClosed"
    class="detail-dialog"
  >
    <div class="detail-dialog__header">
      <div class="title">公告详情</div>
    </div>
    <div class="detail-dialog__body" v-if="detailItem">
      <div class="detail-top">
        <div class="detail-tags">
          <span v-if="detailItem.level === 'urgent'" class="tag tag-urgent"
            >紧急</span
          >
          <span
            v-else-if="detailItem.level === 'important'"
            class="tag tag-important"
            >重要</span
          >
          <span v-else class="tag tag-normal">普通</span>
          <span v-if="detailItem.scope === 'all'" class="tag tag-all">全体</span>
          <span v-else-if="detailItem.scope === 'department'"  class="tag tag-all"
            >部门</span
          >
          <span v-else-if="detailItem.scope === 'user'"  class="tag tag-all">员工</span>
        </div>
        <div class="detail-ops-inline" v-if="!isNotificationMode && isAdmin">
          <img
            src="@/assets/homeOther/edit_icon.png"
            alt="编辑"
            class="op-icon"
            @click.stop="onEditDetail"
          />
          <img
            src="@/assets/homeOther/delete_oa_message.png"
            alt="删除"
            class="op-icon"
            @click.stop="onDeleteDetail"
          />
        </div>
      </div>

      <div class="detail-title">{{ detailItem.title }}</div>

      <div class="detail-meta">
        <div class="meta-item">
          <img src="@/assets/homeOther/oa_message.png" alt="部门" />
          <span>{{ detailItem.department || "行政部" }}</span>
        </div>
        <div class="meta-item">
          <img src="@/assets/homeOther/oa_message_date.png" alt="日期" />
          <span>{{ detailItem.date }}</span>
        </div>
        <!-- <div class="meta-item">
          <img src="@/assets/homeOther/read_oa_message.png" alt="阅读" />
          <span>{{ detailItem.views ?? 0 }}</span>
        </div> -->
      </div>
 <!-- 附件（只读预览） -->
      <div class="detail-attachments" v-if="detailFileList && detailFileList.length">
        <div class="label upload-style-label" >附件</div>
        <VantUploader
          v-model="detailFileList"
          :show-upload-button="false"
          :deletable="false"
          :readonly="true"
        />
      </div>
      <div class="detail-content">{{ detailItem.content || "暂无内容" }}</div>

      <div class="detail-expire" v-if="detailItem.expireTime">
        <span class="dot"></span>
        <span>此公告有效期至：{{ detailItem.expireTime }}</span>
      </div>

     
    </div>
  </van-popup>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, watch, onBeforeUnmount } from "vue";
import { useRouter, useRoute, onBeforeRouteLeave } from "vue-router";
import { showToast } from "vant";
import {
  publishAnnouncement,
  revokeAnnouncement,
  addMessage,
  fetchAllUsers,
  fetchAllDepartments,
  type AddMessageRequest,
  getMessageById,
  readMessage,
  updateMessage,
  deleteMessage,
} from "@/api/message";
import { queryOaMessageListApi, queryMessageApi } from "@/api/home";
import { storage } from "@/utils/storage";
import { getUserById } from "@/api/user";
import VantUploader from "@/components/UploadFiled/VantUploader.vue";
import { openUploadFromRowClick } from "@/utils/uploadTrigger";

const router = useRouter();
const route = useRoute();

// 进入模式：公告管理 or 消息通知（顶部消息入口）
const isNotificationMode = computed(
  () => String(route.query?.mode || "") === "notify"
);

// 搜索与筛选
const keyword = ref("");
const type = ref<"all" | "urgent" | "important" | "normal">("all");
// 筛选范围支持“全部范围(any) / 全体员工(all) / 指定部门(department) / 指定员工(user)”
const scope = ref<"any" | "all" | "department" | "user">("any");
const typeOptions = [
  { text: "全部类型", value: "all" },
  { text: "紧急", value: "urgent" },
  { text: "重要", value: "important" },
  { text: "普通", value: "normal" },
];
const scopeOptions = [
  { text: "全部范围", value: "any" },
  { text: "全体员工", value: "all" },
  { text: "指定部门", value: "department" },
  { text: "指定员工", value: "user" },
];

// 列表数据
const list = ref<any[]>([]);
// 原始数据（用于客户端筛选）
const sourceList = ref<any[]>([]);
const total = ref(0);
const loading = ref(false);

// 详情弹窗状态
const showDetailDialog = ref(false);
const detailItem = ref<any | null>(null);

// 管理员判断：沿用首页逻辑，并做更健壮的兼容
const currentUser = ref<any>(null);
const currentUserDetail = ref<any>(null);
// 兼容后端返回 1/0、"1"/"0"、true/false 等不同形式的管理员标识
const normalizeAdmin = (val: any): boolean => {
  if (val === undefined || val === null) return false;
  if (typeof val === "string") {
    const s = val.trim().toLowerCase();
    return s === "1" || s === "true" || s === "yes";
  }
  if (typeof val === "boolean") return val;
  return Number(val) === 1;
};
const isAdmin = computed(() => {
  const adminFlag = currentUserDetail.value?.admin ?? currentUser.value?.admin;
  return normalizeAdmin(adminFlag);
});

const getCurrentUserInfo = async () => {
  try {
    currentUser.value = storage.getUserInfo() || storage.getItem("userInfo");
    const userId = currentUser.value?.id || currentUser.value?.userId;
    if (userId) {
      const res: any = await getUserById(String(userId));
      if (res?.code === 0) {
        currentUserDetail.value = res?.data || res;
      }
    }
  } catch (e) {
    console.warn("获取用户信息失败:", e);
  }
};

// 类型与状态映射
// 公告类型字典：1-普通，2-重要，3-紧急
const mapTypeToLevel = (
  t: string | number
): "urgent" | "important" | "normal" => {
  const s = String(t);
  switch (s) {
    case "3":
      return "urgent";
    case "2":
      return "important";
    case "1":
      return "normal";
    default:
      return "normal";
  }
};

const mapStatusToState = (
  s: string | number
): "published" | "revoked" | "draft" => {
  const v = String(s);
  if (v === "1") return "published";
  if (v === "2") return "revoked";
  return "draft";
};

// 范围类型字典：1-全体员工，2-指定部门，3-指定员工
const mapAllowTypeToScope = (
  t: string | number
): "all" | "department" | "user" => {
  const s = String(t);
  switch (s) {
    case "1":
      return "all";
    case "2":
      return "department";
    case "3":
      return "user";
    default:
      return "all";
  }
};

// 时间格式化：将毫秒时间戳或纯数字字符串转换为 YYYY-MM-DD
const formatDate = (val: any): string => {
  try {
    if (!val && val !== 0) return "";
    if (typeof val === "number") {
      const d = new Date(val);
      if (isNaN(d.getTime())) return String(val);
      return d.toISOString().slice(0, 10);
    }
    const s = String(val);
    if (/^\d+$/.test(s)) {
      const n = Number(s);
      const d = new Date(n);
      if (isNaN(d.getTime())) return s;
      return d.toISOString().slice(0, 10);
    }
    return s;
  } catch {
    return "";
  }
};

// 将后端返回的数据转换为页面展示需要的结构（公告）
const transformFromOa = (d: any) => {
  const level = mapTypeToLevel(d.messageType);
  const status = mapStatusToState(d.messageStatus);
  const date = d.pushTime || d.createTime || "";
  const scope = mapAllowTypeToScope(d.allowType);
  return {
    id: String(d.id),
    title: d.title,
    level,
    status,
    scope,
    department: d.createName || "",
    date,
    // 原始字段保留，便于后续扩展
    messageType: d.messageType,
    messageStatus: d.messageStatus,
    createTime: d.createTime,
    pushTime: d.pushTime,
    createName: d.createName,
    allowType: d.allowType,
  };
};

// 将通知接口返回的数据转换为页面展示结构（消息通知）
// data.messageRespList: [{ id, title, isRead, messageType, messageStatus, createTime, createId, createName, pushTime }]
const transformFromNotify = (d: any) => {
  const level = mapTypeToLevel(d.messageType);
  const status = mapStatusToState(d.messageStatus ?? "");
  const date = d.pushTime || d.createTime || "";
  return {
    id: String(d.id),
    title: d.title,
    level,
    status,
    // 通知模式不显示范围标签与状态文案/管理员操作
    scope: undefined,
    department: d.createName || "",
    date,
    // 原始字段保留
    messageType: d.messageType,
    messageStatus: d.messageStatus,
    // 读取状态：0 未读，1 已读（兼容字符串/数字）
    isRead: d.isRead,
    isReadFlag: String(d.isRead) === "1",
    createTime: d.createTime,
    pushTime: d.pushTime,
    createName: d.createName,
    createId: d.createId,
  };
};

// 客户端筛选
const applyFilters = () => {
  let arr = [...sourceList.value];
  // 类型筛选
  if (type.value !== "all") {
    arr = arr.filter((it) => it.level === type.value);
  }
  // 发布范围筛选
  if (scope.value !== "any") {
    arr = arr.filter((it) => it.scope === scope.value);
  }
  // 关键词筛选
  const kw = keyword.value.trim();
  if (kw) {
    const lower = kw.toLowerCase();
    arr = arr.filter((it) =>
      String(it.title || "")
        .toLowerCase()
        .includes(lower)
    );
  }
  list.value = arr;
  total.value = arr.length;
};

// 拉取公告列表（根据当前登录用户ID）
const fetchList = async () => {
  try {
    loading.value = true;
    // 优先从当前用户信息获取ID
    let userId =
      currentUserDetail.value?.id ||
      currentUser.value?.id ||
      currentUser.value?.userId;
    if (!userId) {
      await getCurrentUserInfo();
      userId =
        currentUserDetail.value?.id ||
        currentUser.value?.id ||
        currentUser.value?.userId;
    }
    if (!userId) {
      showToast("未获取到用户信息");
      return;
    }

    const res: any = await queryOaMessageListApi(String(userId));
    if (res?.code === 0 && Array.isArray(res?.data)) {
      const transformed = res.data.map(transformFromOa);
      sourceList.value = transformed;
      applyFilters();
    } else {
      showToast(res?.msg || "获取列表失败");
    }
  } catch (e) {
    console.error(e);
    showToast("获取列表失败");
  } finally {
    loading.value = false;
  }
};

// 拉取通知列表（顶部消息入口）
const fetchNotifyList = async () => {
  try {
    loading.value = true;
    // 优先从当前用户信息获取ID
    let userId =
      currentUserDetail.value?.id ||
      currentUser.value?.id ||
      currentUser.value?.userId;
    if (!userId) {
      await getCurrentUserInfo();
      userId =
        currentUserDetail.value?.id ||
        currentUser.value?.id ||
        currentUser.value?.userId;
    }
    if (!userId) {
      showToast("未获取到用户信息");
      return;
    }

    const res: any = await queryMessageApi(String(userId));
    // 返回结构：{ code, msg, data: { totalUnread, messageRespList: [] } }
    const listData = res?.data?.messageRespList;
    if (res?.code === 0 && Array.isArray(listData)) {
      const transformed = listData.map(transformFromNotify);
      sourceList.value = transformed;
      applyFilters();
    } else {
      showToast(res?.msg || "获取消息失败");
    }
  } catch (e) {
    console.error(e);
    showToast("获取消息失败");
  } finally {
    loading.value = false;
  }
};

const onSearch = () => applyFilters();

// 前端筛选完善：对搜索关键词、类型、范围的变化进行实时筛选
// 1) 搜索框：仅根据标题进行模糊匹配（大小写不敏感）
// 2) 类型筛选：前端基于 level 字段在客户端过滤
// 3) 范围筛选：前端基于 scope 字段在客户端过滤（公告模式）
// 为了更平滑的输入体验，对搜索关键词增加轻微防抖
let keywordDebounceTimer: any = null;
watch(keyword, () => {
  if (keywordDebounceTimer) clearTimeout(keywordDebounceTimer);
  keywordDebounceTimer = setTimeout(() => {
    applyFilters();
  }, 200);
});

// 类型与范围变化时立即筛选
watch(type, () => {
  applyFilters();
});

watch(scope, () => {
  applyFilters();
});

const onPublish = async (item: any) => {
  // 权限拦截：非管理员不可发布
  if (!isAdmin.value) {
    showToast("无权限操作");
    return;
  }
  try {
    const res: any = await publishAnnouncement(item.id);
    if (res?.code === 0) {
      item.status = "published";
      showToast("已发布");
    } else {
      showToast(res?.msg || "发布失败");
    }
  } catch (e) {
    showToast("发布失败");
  }
};

const onRevoke = async (item: any) => {
  // 权限拦截：非管理员不可撤回
  if (!isAdmin.value) {
    showToast("无权限操作");
    return;
  }
  try {
    const res: any = await revokeAnnouncement(item.id);
    if (res?.code === 0) {
      // 撤回后展示“已撤回”状态
      item.status = "revoked" as any;
      showToast("已撤回");
    } else {
      showToast(res?.msg || "撤回失败");
    }
  } catch (e) {
    showToast("撤回失败");
  }
};

// ====== 详情弹窗 ======
const buildDetailItem = (d: any, fallback: any = {}) => {
  const level = mapTypeToLevel(
    d?.messageType ?? fallback?.messageType ?? fallback?.level
  );
  const scope = d?.allowType
    ? mapAllowTypeToScope(d.allowType)
    : fallback?.scope ?? "all";
  const department = d?.createName ?? fallback?.department ?? "行政部";
  const date = formatDate(d?.pushTime ?? d?.createTime ?? fallback?.date ?? "");
  const content = d?.context ?? d?.content ?? fallback?.content ?? "";
  const expireTime = d?.expireTime ?? fallback?.expireTime;
  const views = d?.views ?? fallback?.views ?? 0;
  return {
    id: String(d?.id ?? fallback?.id ?? ""),
    title: d?.title ?? fallback?.title ?? "",
    level,
    scope,
    department,
    date,
    content,
    expireTime,
    views,
  };
};

const openDetail = async (item: any) => {
  try {
    let res: any;
    if (isNotificationMode.value) {
      // 从首页消息入口进入的通知模式：点击详情调用“已读并返回详情”接口
      res = await readMessage(String(item.id));
      // 本地标记为已读（若存在 isRead 字段）
      if (item && typeof item === "object" && "isRead" in item) {
        try {
          (item as any).isRead = 1;
        } catch {}
      }
    } else {
      res = await getMessageById(String(item.id));
    }
    const detail = res?.data; // 后端返回 data 为详情对象
    detailItem.value = buildDetailItem(detail || item, item);
    // 详情附件只读展示
    const attStr = String(detail?.attachmentUrl || "");
    detailFileList.value = buildUploaderItemsFromAttachmentUrl(attStr);
    showDetailDialog.value = true;
  } catch (e) {
    // 即便失败，也用现有列表数据兜底展示
    detailItem.value = buildDetailItem(item, item);
    detailFileList.value = [];
    showDetailDialog.value = true;
  }
};

// 详情操作占位（与设计稿一致，后续与后端联调具体接口）
const onEditDetail = () => {
  if (!isAdmin.value) {
    showToast("无权限操作");
    return;
  }
  // 关闭详情弹窗，打开新增弹窗（编辑模式）并回显详情数据
  openEditDialogFromDetail();
};

const onDeleteDetail = () => {
  if (!isAdmin.value) {
    showToast("无权限操作");
    return;
  }
  if (!detailItem.value?.id) {
    showToast("缺少公告ID");
    return;
  }
  handleDelete(String(detailItem.value.id));
};

const onShareDetail = () => {
  showToast("分享功能待联调");
};

// 详情弹窗关闭后，清空详情数据，避免保留上次内容
const onDetailDialogClosed = () => {
  detailItem.value = null;
  detailFileList.value = [];
};

// 路由离开或组件卸载时，统一清理弹窗与临时状态，避免缓存残留
onBeforeRouteLeave(() => {
  // 关闭并清空详情弹窗数据
  showDetailDialog.value = false;
  detailItem.value = null;
  detailFileList.value = [];
  // 关闭并重置新增弹窗
  showAddDialog.value = false;
  resetAddForm();
  // 清理搜索防抖定时器
  if (keywordDebounceTimer) {
    clearTimeout(keywordDebounceTimer);
    keywordDebounceTimer = null;
  }
});

onBeforeUnmount(() => {
  // 关闭并清空详情弹窗数据
  showDetailDialog.value = false;
  detailItem.value = null;
  detailFileList.value = [];
  // 关闭并重置新增弹窗
  showAddDialog.value = false;
  resetAddForm();
  // 清理搜索防抖定时器
  if (keywordDebounceTimer) {
    clearTimeout(keywordDebounceTimer);
    keywordDebounceTimer = null;
  }
});

const goBack = () => router.back();
// 打开新增弹窗（仅管理员可见/可操作）
const showAddDialog = ref(false);
const isEditMode = ref(false);
const editingId = ref<string | number | null>(null);
const isSubmittingAdd = ref(false);
const openAddDialog = () => {
  if (!isAdmin.value) {
    showToast("无权限操作");
    return;
  }
  // 每次点击“新增”都重置表单，避免保留上一次的数据
  resetAddForm();
  showAddDialog.value = true;
};

onMounted(async () => {
  await getCurrentUserInfo();

  if (!isNotificationMode.value) {
    // 仅公告模式尝试使用首页预取的数据，提升首屏体验
    try {
      const raw =
        storage.getItem?.("oaMessagePrefetch") ??
        sessionStorage.getItem("oaMessagePrefetch");
      if (raw) {
        const arr = Array.isArray(raw) ? raw : JSON.parse(String(raw));
        if (Array.isArray(arr) && arr.length) {
          sourceList.value = arr.map(transformFromOa);
          applyFilters();
        }
      }
    } catch (e) {
      // ignore
    }
    // 拉取公告列表
    fetchList();
  } else {
    // 拉取通知列表
    fetchNotifyList();
  }
});

// 状态显示文案与样式映射
const statusText = (status: string) => {
  switch (status) {
    case "published":
      return "已发布";
    case "revoked":
      return "已撤回";
    default:
      return "未发布";
  }
};

const statusClass = (status: string) => {
  switch (status) {
    case "published":
      return "status-published";
    case "revoked":
      return "status-revoked";
    default:
      return "status-draft";
  }
};

// ====== 新增公告弹窗相关 ======
const addTitle = ref("");
const addType = ref<"urgent" | "important" | "normal">("important");
const addScope = ref<"all" | "user" | "department">("all");
const addContent = ref("");
// 选择器弹窗状态
const showTypePicker = ref(false);
const showScopePicker = ref(false);
// 显示文案映射
const typeLabelMap: Record<string, string> = {
  urgent: "紧急公告",
  important: "重要公告",
  normal: "普通公告",
};
const scopeLabelMap: Record<string, string> = {
  all: "全体员工",
  user: "指定员工",
  department: "指定部门",
};
// Picker 列配置
const addTypePickerColumns = [
  { text: "紧急公告", value: "urgent" },
  { text: "重要公告", value: "important" },
  { text: "普通公告", value: "normal" },
];
const addScopePickerColumns = [
  { text: "全体员工", value: "all" },
  { text: "指定部门", value: "department" },
  { text: "指定员工", value: "user" },
];
const availableTargets = ref<Array<{ id: string | number; name: string }>>([]);
const selectedTargetIds = ref<Array<number>>([]);
// 上传附件
const messageUploaderRef = ref<any>(null);
const messageFileList = ref<any[]>([]);
const uploadedFiles = ref("");
// 编辑模式下记录原始附件字符串，用于提交时判断是否发生变更
const originalAttachmentUrl = ref("");
const openMessageUploaderInput = (e: Event) => {
  openUploadFromRowClick(e as any, messageUploaderRef.value);
};

// 详情附件（只读）展示用
const detailFileList = ref<any[]>([]);
// 将后端 attachmentUrl（逗号分隔路径）转换为上传控件可识别的文件条目
const buildUploaderItemsFromAttachmentUrl = (urls: string) => {
  if (!urls) return [] as any[];
  try {
    const parts = String(urls)
      .split(",")
      .map((s) => s.trim())
      .filter(Boolean);
    return parts.map((p) => {
      const clean = p.replace(/\\/g, "/");
      const name = clean.split("/").pop() || clean;
      return { name, serverPath: clean };
    });
  } catch {
    return [] as any[];
  }
};

// 规范化附件路径字符串，避免反斜杠和多余空格导致的比较误差
const normalizePathList = (s?: string) => {
  try {
    return String(s || "")
      .split(",")
      .map((p) => String(p || "").trim().replace(/\\/g, "/"))
      .filter(Boolean)
      .join(",");
  } catch {
    return "";
  }
};

// 收集当前文件列表中的所有附件路径（既包括已有也包括本次上传）
const collectAllAttachmentPaths = (list: any[]) => {
  try {
    return (Array.isArray(list) ? list : [])
      .map((f: any) => f.uploadedPath || f.serverPath || f.path)
      .filter(Boolean)
      .map((p: any) => String(p).replace(/\\/g, "/"))
      .join(",");
  } catch {
    return "";
  }
};

// 仅收集本次会话中新上传的附件路径，避免后端重复移动旧文件
const collectNewAttachmentPaths = (list: any[]) => {
  try {
    return (Array.isArray(list) ? list : [])
      .filter((f: any) => !!f.uploadedPath)
      .map((f: any) => f.uploadedPath || f.serverPath)
      .filter(Boolean)
      .map((p: any) => String(p).replace(/\\/g, "/"))
      .join(",");
  } catch {
    return "";
  }
};

// 映射关系（如后端有不同约定可调整）
// 新字典：1-普通，2-重要，3-紧急
const messageTypeMap: Record<string, string> = {
  urgent: "3",
  important: "2",
  normal: "1",
};
// 新字典：1-全体员工，2-指定部门，3-指定员工
const allowTypeMap: Record<string, string> = {
  all: "1",
  department: "2",
  user: "3",
};

// 根据发布范围加载可选目标
const loadTargets = async () => {
  try {
    if (addScope.value === "user") {
      const res = await fetchAllUsers();
      if (res.code === 0) {
        availableTargets.value = res.data;
      }
    } else if (addScope.value === "department") {
      const res = await fetchAllDepartments();
      if (res.code === 0) {
        availableTargets.value = res.data;
      }
    } else {
      availableTargets.value = [];
      selectedTargetIds.value = [];
    }
  } catch (e) {
    console.warn("加载指定对象失败:", e);
  }
};

const isRestoringTargets = ref(false);
watch(addScope, async () => {
  if (isRestoringTargets.value) {
    await loadTargets();
    return;
  }
  selectedTargetIds.value = [];
  await loadTargets();
});

const toggleTarget = (id: string | number) => {
  const nid = Number(id);
  if (Number.isNaN(nid)) return;
  const idx = selectedTargetIds.value.findIndex((x) => x === nid);
  if (idx >= 0) selectedTargetIds.value.splice(idx, 1);
  else selectedTargetIds.value.push(nid);
};

// 同步上传结果为逗号分隔的服务器路径字符串
watch(
  messageFileList,
  (list) => {
    const paths = (list || [])
      .map((f: any) => f.serverPath)
      .filter(Boolean)
      .join(",");
    uploadedFiles.value = paths;
  },
  { deep: true }
);

const onTypeConfirm = (params: any) => {
  // Vant4 Picker confirm 事件兼容处理
  const opt = Array.isArray(params?.selectedOptions)
    ? params.selectedOptions[0]
    : params;
  const val = opt?.value ?? opt;
  addType.value = val as any;
  showTypePicker.value = false;
};

const onScopeConfirm = (params: any) => {
  const opt = Array.isArray(params?.selectedOptions)
    ? params.selectedOptions[0]
    : params;
  const val = opt?.value ?? opt;
  addScope.value = val as any;
  showScopePicker.value = false;
};

const onSubmitAdd = async () => {
  if (isSubmittingAdd.value) return; // 防止重复提交
  // 权限拦截：非管理员不可新增
  if (!isAdmin.value) {
    showToast("无权限操作");
    return;
  }
  if (!addTitle.value.trim()) {
    showToast("请填写公告标题");
    return;
  }
  if (!addContent.value.trim()) {
    showToast("请填写公告内容");
    return;
  }
  if (addScope.value !== "all" && selectedTargetIds.value.length === 0) {
    showToast("请选择指定对象");
    return;
  }

  const basePayload: any = {
    title: addTitle.value.trim(),
    context: addContent.value.trim(),
    messageType: messageTypeMap[addType.value],
    allowType: allowTypeMap[addScope.value],
    allowValue:
      addScope.value === "all" ? "0" : selectedTargetIds.value.join(","),
  };

  // 根据当前文件列表构建附件路径
  const allPaths = collectAllAttachmentPaths(messageFileList.value);
  const newPaths = collectNewAttachmentPaths(messageFileList.value);

  if (!isEditMode.value) {
    // 新增：仅在存在附件时发送字段，避免后端对空字符串进行文件移动
    if (allPaths) {
      basePayload.attachmentUrl = allPaths;
    }
  } else {
    // 修改：避免重复移动旧文件，仅在附件发生变化或新增时发送
    const old = normalizePathList(originalAttachmentUrl.value);
    const current = normalizePathList(allPaths);
    if (!old && !current) {
      // 都为空，不发送附件字段
    } else if (old === current) {
      // 未变化，不发送附件字段
    } else if (newPaths) {
      // 仅发送本次新增附件路径
      basePayload.attachmentUrl = newPaths;
    } else if (!current && !!old) {
      // 用户清空了附件：显式发送空字符串表示删除
      basePayload.attachmentUrl = "";
    } else {
      // 兜底：发送当前列表（如确有变更但无法区分新旧）
      basePayload.attachmentUrl = current;
    }
  }

  try {
    isSubmittingAdd.value = true;
    let res: any;
    if (isEditMode.value && editingId.value) {
      res = await updateMessage({ id: editingId.value, ...basePayload });
    } else {
      res = await addMessage(basePayload);
    }

    if (res?.code === 0 || res?.code === 200) {
      showToast(isEditMode.value ? "修改成功" : "新增成功");
      showAddDialog.value = false;
      // 重置编辑状态与表单
      isEditMode.value = false;
      editingId.value = null;
      addTitle.value = "";
      addType.value = "important";
      addScope.value = "all";
      addContent.value = "";
      availableTargets.value = [];
      selectedTargetIds.value = [];
      // 刷新列表
      fetchList();
    } else {
      showToast(res?.msg || (isEditMode.value ? "修改失败" : "新增失败"));
    }
  } catch (e) {
    showToast(isEditMode.value ? "修改失败" : "新增失败");
  } finally {
    isSubmittingAdd.value = false;
  }
};

// 重置新增/编辑表单到初始状态
const resetAddForm = () => {
  // 基本状态
  isEditMode.value = false;
  editingId.value = null;
  isSubmittingAdd.value = false;

  // 表单字段
  addTitle.value = "";
  addType.value = "important";
  addScope.value = "all";
  addContent.value = "";

  // 指定对象 & 附件
  availableTargets.value = [];
  selectedTargetIds.value = [];
  uploadedFiles.value = "";
  originalAttachmentUrl.value = "";
  messageFileList.value = [];

  // 选择器弹窗状态
  showTypePicker.value = false;
  showScopePicker.value = false;
};

// 弹窗关闭后统一清空上一次的数据（包括取消与点击关闭按钮）
const onAddDialogClosed = () => {
  resetAddForm();
};

// 从详情数据回显到编辑弹窗
const openEditDialogFromDetail = async () => {
  try {
    const id = String(detailItem.value?.id || "");
    if (!id) {
      showToast("缺少公告ID");
      return;
    }
    const res: any = await getMessageById(id);
    const d = res?.data || {};
    // 回显：标题、内容
    addTitle.value = d.title || detailItem.value?.title || "";
    addContent.value = d.context || detailItem.value?.content || "";

    // 回显：类型与范围（将服务端编码映射到前端枚举）
    const typeCode = String(d.messageType ?? "");
    const scopeCode = String(d.allowType ?? "");
    // 反向映射：1-普通 2-重要 3-紧急
    const inverseTypeMap: Record<string, any> = { "3": "urgent", "2": "important", "1": "normal" };
    // 反向映射：1-全体员工 2-指定部门 3-指定员工
    const inverseScopeMap: Record<string, any> = { "1": "all", "2": "department", "3": "user" };
    addType.value = (inverseTypeMap[typeCode] || detailItem.value?.level || "important") as any;
    // 编辑回显时，暂时抑制 addScope 的 watch 清空 selectedTargetIds
    isRestoringTargets.value = true;
    addScope.value = (inverseScopeMap[scopeCode] || detailItem.value?.scope || "all") as any;
    await loadTargets();

    // 回显：指定对象
    const allowValue = String(d.allowValue ?? "0");
    if (allowValue && allowValue !== "0") {
      selectedTargetIds.value = allowValue
        .split(",")
        .map((s) => Number(s))
        .filter((n) => !Number.isNaN(n));
    } else {
      selectedTargetIds.value = [];
    }

    // 回显：附件URL，并同步填充到上传控件用于预览
    uploadedFiles.value = String(d.attachmentUrl ?? "");
    originalAttachmentUrl.value = normalizePathList(uploadedFiles.value);
    messageFileList.value = buildUploaderItemsFromAttachmentUrl(uploadedFiles.value);

    // 切换编辑模式
    isEditMode.value = true;
    editingId.value = id;

    // 打开编辑弹窗，关闭详情弹窗
    showDetailDialog.value = false;
    showAddDialog.value = true;
    // 恢复 addScope 的正常 watch 行为
    isRestoringTargets.value = false;
  } catch (e) {
    showToast("获取详情失败，无法编辑");
  }
};

// 删除当前详情项
const handleDelete = async (id: string) => {
  try {
    const res: any = await deleteMessage(id);
    if (res?.code === 0 || res?.code === 200) {
      showToast("删除成功");
      showDetailDialog.value = false;
      fetchList();
    } else {
      showToast(res?.msg || "删除失败");
    }
  } catch (e) {
    showToast("删除失败");
  }
};
</script>

<style lang="scss" scoped>
@import "./style/index.scss";

/* 详情弹窗样式，贴近设计稿效果 */
.detail-dialog {
  width: min(94vw, 640px);
  max-width: 640px;
  background: #fff;
  border-radius: 18px;
  padding: 48px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.16);
  overflow: hidden;

  .detail-dialog__header {
    position: relative;
    padding-top: 4px;
    margin-bottom: 12px;

    .title {
      font-weight: bold;
      font-size: 36px;
      color: #171a1d;
      text-align: center;
      margin-top: 33px;
      margin-bottom: 25px;
    }
    .ops {
      position: absolute;
      right: 8px;
      top: 0;
      display: flex;
      align-items: center;
      gap: 14px;
      .op-icon {
        width: 22px;
        height: 22px;
        cursor: pointer;
      }
      .op-icon:active {
        opacity: 0.85;
      }
    }
  }

  .detail-dialog__body {
    .detail-top {
      display: flex;
      align-items: center;
      justify-content: space-between;
        margin-bottom: 23px;
    }
    .detail-tags {
      display: flex;
      gap: 10px;
    
      .tag {
        width: 72px;
        height: 32px;
        line-height: 32px;
        border-radius: 30px;
        font-family: "Source Han Sans CN", "Source Han Sans CN";
        font-weight: 500;
        font-size: 24px;
      }

      .tag-urgent {
        background: #ffd9d9;
        color: #d91619;
      }

      .tag-important {
        background: #fef9c3;
        color: #8b571b;
      }

      .tag-normal {
        background: #dbeafe;
        color: #2764eb;
      }

      .tag-all {
        background: #f3f4f6;
        color: #6f7681;
        border: 1px solid rgba(0, 0, 0, 0.1);
      }
    }

    .detail-ops-inline {
      display: inline-flex;
      align-items: center;
      gap: 14px;
      .op-icon {
        width: 38px;
        height: 38px;
        cursor: pointer;
      }
      .op-icon:active {
        opacity: 0.85;
      }
    }

    .detail-title {
      font-weight: bold;
      font-size: 32px;
      color: #171a1d;
      margin-top: 23px;
      margin-bottom: 10px;
    }

    .detail-meta {
      display: flex;
      align-items: center;
      gap: 18px;
      margin-bottom: 29px;
      .meta-item {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        font-weight: 400;
        font-size: 24px;
        color: #666666;
        img {
          width: 26px;
          height: 26px;
        }
      }
    }
  .upload-style-label{
    font-weight: 400;
font-size: 24px;
color: #666666;
  }
    .detail-content {
      font-weight: 400;
      font-size: 28px;
      color: #171a1d;
    }

    .detail-expire {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 13px;
      color: #f2a200;
      .dot {
        width: 8px;
        height: 8px;
        border-radius: 50%;
        background: #f2a200;
      }
    }
  }
}
</style>